#include "input_manager.h"
#include  <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

#define BufferLen 20

/*构造一个链表，用于注册底层触摸屏，net的结构体*/ 
static PInputDevice g_ptIntPutDevs = NULL;//
 
static int g_iWrite = 0;
static int g_iRead = 0;
static InputEvent g_atInputEvent[BufferLen] ;

static pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER;//初始化条件变量
static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;//初始化互斥量

/*
 * @Description: 输入设备把数据放到环形缓冲区
 * @param 1 – 参数 1.发送数据的结构体指针
 * @return – 无返回值
 * @others – 如果read的值与write+1的值相等，说明环形缓冲区满了，未满就应该放
 */

static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{
    if(g_iRead != ((g_iWrite+1)%BufferLen))
    {
        g_atInputEvent[g_iWrite] = *ptInputEvent;
        g_iWrite = (g_iWrite + 1) % BufferLen;
    }
}

/*
 * @Description: 上层APP从环形缓冲区读取数据
 * @param 1 – 参数 1.数据存放的结构体指针
 * @return – 1为成功，0为失败
 * @others – 如果read的值与write的值相等，说明环形缓冲区满了，未满就应该取走
 */
static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{
    if(g_iRead != g_iWrite)
    {
        *ptInputEvent = g_atInputEvent[g_iRead];
        g_iRead = (g_iRead + 1) % BufferLen;
        return 1;
    }
    else
    {
        return 0;
    }   
}

/*
 * @Description: 接受设备数据的子线程
 * @param 1 – 参数 1.对应设备的结构体指针
 * @return – 无返回值
 * @others – 读取数据，保存数据，唤醒等待数据的线程
 */
static void *input_recv_thread_func(void *date)
{
    PInputDevice ptDevinput = (PInputDevice)date;
    InputEvent tInputEvent ;
    int ret ;
    while(1)
    {
        /*调用结构体中的getbuf函数读取数据*/
        ret = ptDevinput->GetInputEvent(&tInputEvent);
        /*保存数据到一个足够大的buf中（环形缓冲区）*/    
        if(!ret)
        {
            pthread_mutex_lock(&mymutex);//加锁
            PutInputEventToBuffer(&tInputEvent);
            /*唤醒等待数据的线程*/
            pthread_cond_signal(&myconvar);//通知子线程
            pthread_mutex_unlock(&mymutex);//解锁
        }
    }
    return NULL;
}

/*
 * @Description: 给底层设备使用的注册函数
 * @param 1 – PDispOpr ptInPutOpr .设备的结构体指针
 * @return – 无返回值
 * @others – 传入结构体指针，把底层设备的结构体用头插法插进g_ptIntPutDevs这个链表中
 */
void RegisterInPut(PInputDevice ptInPutOpr) 
{
    ptInPutOpr->ptNext = g_ptIntPutDevs;//链表头插入
    g_ptIntPutDevs = ptInPutOpr;
}


/*
 * @Description: 注册设备链表
 * @param 1 – 无
 * @return – 无返回值
 * @others – 把net和触摸屏的结构体注册进g_ptIntPutDevs这个链表中
 */
void InPutInit(void)
{
    extern void TouchInPutDevRegister(void);
    TouchInPutDevRegister();
    extern void NetInPutDevRegister(void);
    NetInPutDevRegister(); 
}



/*
 * @Description: 初始化设备，创建子线程
 * @param 1 – 无参数
 * @return – 无返回值
 * @others – 遍历链表，初始化链表中注册的设备，并对每个设备创建一个接受信息的子线程
 */
void IntPutDevInit (void)
{   
    pthread_t tid;
    int ret =0;
    PInputDevice Ptemp = g_ptIntPutDevs;//局部变量储存已经注册的显示设备
    while(Ptemp)
    {/*遍历链表*/

        ret = Ptemp->InputInin();
        if(!ret)
        {
        ret = pthread_create(&tid, NULL,input_recv_thread_func, Ptemp);//创建一个子线程my_thread_func
        }
        /*进入下一个结构体初始化下一个设备*/
        Ptemp = Ptemp->ptNext;
    }

}
 

/*
 * @Description: 获取输入设备数据的函数（被上层函数调用）
 * @param 1 – 参数 1.储存输入数据的结构体
 * @return – 返回值,必要时对返回值作出说明
 * @others – 无数据就休眠，有数据就返回数据
 */
int GetInPutEvent (PInputEvent ptevent)
{
    int ret ;
    /*多线程访问环形缓冲区，访问前要上锁*/
    pthread_mutex_lock(&mymutex);//加锁
    /*获取环形缓冲区数据数据*/
    ret = GetInputEventFromBuffer(ptevent);
    if(ret == 1)
    {      
        pthread_mutex_unlock(&mymutex);//解锁
        return 0;
    }
    else
    {
        /*无数据就休眠*/
        pthread_cond_wait(&myconvar,&mymutex);//等待条件变量
        /*有数据就返回数据*/
        ret = GetInputEventFromBuffer(ptevent);
        if(ret == 1)
        {
            ret =0;
        }
        else{
            ret = -1;
        }
        pthread_mutex_unlock(&mymutex);//解锁
    }
    return ret ;
    
}





